package com.yanx.codegen;

import cn.hutool.core.util.ClassUtil;
import com.yanx.codegen.annotation.CodeGenClass;
import com.yanx.codegen.annotation.CodeGenField;
import com.yanx.common.utils.File_;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.core.io.ClassPathResource;

import javax.persistence.Entity;
import javax.persistence.Table;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author gotanks
 * @date 2021-8-22
 */
public class CodeGenerator {

    private static boolean isOverride = false;

    private static List<CodeGenType> types = new ArrayList<>();

    /**
     * 根据JPA的entity生成代码
     *
     * @param scanPackage 扫描包
     */
    public static void generatorWithEntity(String scanPackage) {
        generatorWithEntity(scanPackage, new Class[]{});
    }

    /**
     * 根据JPA的entity生成代码
     *
     * @param scanPackage 扫描包
     * @param override    是否覆盖
     */
    public static void generatorWithEntity(String scanPackage, boolean override) {
        generatorWithEntity(scanPackage, new Class[]{}, override);
    }

    /**
     * 根据JPA的entity生成代码
     *
     * @param scanPackage 扫描包
     * @param entities    指定生成类
     */
    public static void generatorWithEntity(String scanPackage, Class... entities) {
        generatorWithEntity(scanPackage, CodeGenType.ALL(), entities);
    }

    /**
     * 根据JPA的entity生成代码
     *
     * @param scanPackage 扫描包
     * @param entities    指定生成类
     * @param override    是否覆盖
     */
    public static void generatorWithEntity(String scanPackage, Class[] entities, boolean override) {
        generatorWithEntity(scanPackage, CodeGenType.ALL(), entities, override);
    }

    /**
     * 根据JPA的entity生成代码
     *
     * @param scanPackage  扫描包
     * @param codeGenTypes 生成类的类型
     * @param entities     指定生成类
     */
    public static void generatorWithEntity(String scanPackage, CodeGenType[] codeGenTypes, Class... entities) {
        generatorWithEntity(scanPackage, codeGenTypes, entities, false);
    }

    /**
     * 根据JPA的entity生成代码
     *
     * @param scanPackage  扫描包
     * @param codeGenTypes 生成类的类型
     * @param entities     指定生成类
     * @param override     是否覆盖
     */
    public static void generatorWithEntity(String scanPackage, CodeGenType[] codeGenTypes, Class[] entities, boolean override) {
//        String scanPackage = CodeGenerator.class.getPackage().getName();
        List<MyClass> myClassList = new ArrayList<>();
        Set<Class<?>> classSet = ClassUtil.scanPackageByAnnotation(scanPackage, Entity.class);
        for (Class<?> aClass : classSet) {
            CodeGenClass codeGenClass = aClass.getAnnotation(CodeGenClass.class);
            if (codeGenClass == null) {
                continue;
            }
            if (entities != null && entities.length > 0) {
                boolean contains = false;
                for (Class entity : entities) {
                    if (entity.equals(aClass)) {
                        contains = true;
                    }
                }
                if (!contains) {
                    continue;
                }
            }
            MyClass myClass = new MyClass();
            isOverride = override;
            types = Arrays.asList(codeGenTypes);
            myClass.setLabelName(codeGenClass.value());
            myClass.setIdType(codeGenClass.idType().getSimpleName());
            myClass.setAuthor(codeGenClass.author());
            myClass.setClassName(aClass.getSimpleName());
//            myClass.setModuleName(moduleName);
            Table table = aClass.getAnnotation(Table.class);
            myClass.setTableName(table.name().toUpperCase());
            myClass.setBasePackage(scanPackage);
            myClass.setBasePath(myClass.getClass().getResource("/").getPath());
            Field[] declaredFields = ClassUtil.getDeclaredFields(aClass);
            for (Field declaredField : declaredFields) {
                MyField myField = new MyField();
                myField.setFieldName(declaredField.getName());
                myField.setFieldType(declaredField.getType().getSimpleName());
                CodeGenField fieldCodeGenField = declaredField.getAnnotation(CodeGenField.class);
                if (fieldCodeGenField != null) {
                    myField.setFieldRemark(fieldCodeGenField.value());
                    if (fieldCodeGenField.dto()) {
                        myClass.getDtoFields().add(myField);
                    }
                    if (fieldCodeGenField.vo()) {
                        myClass.getVoFields().add(myField);
                    }
                    if (fieldCodeGenField.qo()) {
                        myClass.getQoFields().add(myField);
                    }
                }
            }
            myClassList.add(myClass);
        }
        generatorAllFile(myClassList);

    }

    public static void generatorAllFile(List<MyClass> myClassList) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (MyClass myClass : myClassList) {
            Map<String, Object> map = myClass.toMap();
            mapList.add(map);
            String className = myClass.getClassName();

            System.out.println("|---开始生成 " + className + " 相关类：");
            //生成Dto
            if (types.contains(CodeGenType.Dto)) {
                generator(map, className + "Dto.java", "dto.ftl", myClass.getDtoPath());
            }

            //生成Vo
            if (types.contains(CodeGenType.Vo)) {
                generator(map, className + "Vo.java", "vo.ftl", myClass.getVoPath());
            }

            //生成Qo
            if (types.contains(CodeGenType.Qo)) {
                generator(map, className + "Qo.java", "qo.ftl", myClass.getQoPath());
            }

            //生成Repository
            if (types.contains(CodeGenType.Repository)) {
                generator(map, className + "Repository.java", "repository.ftl", myClass.getRepositoryPath());
            }

            //生成Manager
            if (types.contains(CodeGenType.Manager)) {
                generator(map, className + "Manager.java", "manager.ftl", myClass.getManagerPath());
            }

            //生成Command
            if (types.contains(CodeGenType.Cmd)) {
                generator(map, className + "CreateCmd.java", "cmd-create.ftl", myClass.getCommandPath());
                generator(map, className + "UpdateCmd.java", "cmd-update.ftl", myClass.getCommandPath());
                generator(map, className + "DeleteCmd.java", "cmd-delete.ftl", myClass.getCommandPath());
            }

            //生成Api
            if (types.contains(CodeGenType.Api)) {
                generator(map, className + "Api.java", "api.ftl", myClass.getApiPath());
            }

            //生成Mapper
            if (types.contains(CodeGenType.Mapper)) {
                generator(map, className + "Mapper.java", "mapper.ftl", myClass.getMapperPath());
            }

            //生成Qry
            if (types.contains(CodeGenType.Qry)) {
                generator(map, className + "ByIdQry.java", "qry-by-id.ftl", myClass.getQueryPath());
                generator(map, className + "ListQry.java", "qry-list.ftl", myClass.getQueryPath());
            }

            System.out.println("|---结束生成 " + className + " 相关类。");
            System.out.println("");
        }

//        //生成Projections
//        if (types.contains(CodeGenType.Qry)) {
//            MyClass oneClass = myClassList.get(0);
//            Map<String, Object> map = oneClass.toMap();
//            map.put("classList", mapList);
//            generator(map, "ProjectionsUtil.java", "projections.ftl", oneClass.getUtilsPath());
//        }
    }

    public static void generator(Map<String, Object> dataMap, String fileName, String templateName, String classPath) {
        // step1 创建freeMarker配置实例
        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);

        // step2 生成数据
        File packagePath = new File(classPath);
        if (!packagePath.exists()) {
            packagePath.mkdirs();
        }
        File docFile = new File(classPath + "\\" + fileName);
        if (docFile.exists()) {
            if (isOverride) {
                System.out.println("|-----" + fileName + "被覆盖 !");
            } else {
                System.out.println("|-----" + fileName + "已存在 !");
                return;
            }
        }
        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)))) {
            // step3 获取模版路径
            ClassPathResource classPathResource = new ClassPathResource("templates/ftl/generator/" + templateName);
            InputStream inputStream = classPathResource.getInputStream();
            File pack = new File("ftl");
            if (!pack.exists()) {
                pack.mkdirs();
            }
            File dest = new File(pack, templateName);
            File_.writeFromStream(inputStream, dest);
            configuration.setDirectoryForTemplateLoading(pack);

            // step4 加载模版文件
            Template template = configuration.getTemplate(templateName);

            // step5 输出文件
            template.process(dataMap, out);
            System.out.println("|-----" + fileName + "文件创建成功 !");

            dest.delete();
            pack.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
